using System;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using Microsoft.Xaml.Behaviors;
using WPFTemplateLib.Adorners;
/*
* 源码已托管：https://gitee.com/dlgcy/WPFTemplateLib
* 版本：2024年10月10日
*/
namespace WPFTemplateLib.Behaviors
{
	/// <summary>
	/// [行为] 附加装饰器[<see cref="BindableContainerAdorner"/>]（通过设置 <see cref="Element"/> 属性）
	/// <para/>已知问题：设计时不显示。可使用 AttachAdornerHelper 解决。
	/// </summary>
	public class AttachAdornerBehavior : Behavior<UIElement>
	{
		/// <summary>
		/// 作为装饰内容的界面元素
		/// </summary>
		public FrameworkElement Element { get; set; }

		/// <summary>
		/// 显示的 Adorner
		/// </summary>
		private Adorner _theAdorner;

		#region [依赖属性] 是否显示 Adorner
		/// <summary>
		/// 是否显示 Adorner
		/// </summary>
		public bool IsShowAdorner
		{
			get => (bool)GetValue(IsShowAdornerProperty);
			set => SetValue(IsShowAdornerProperty, value);
		}
		/// <summary>
		/// [依赖属性] 是否显示 Adorner
		/// </summary>
		public static readonly DependencyProperty IsShowAdornerProperty =
			 DependencyProperty.Register(nameof(IsShowAdorner), typeof(bool), typeof(AttachAdornerBehavior), new PropertyMetadata(true, IsShowAdornerChangedCallback));
		/// <summary>
		/// 是否显示 Adorner 变动处理方法
		/// </summary>
		private static void IsShowAdornerChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var instance = d as AttachAdornerBehavior;
			if(instance == null)
				return;

			if((bool)e.NewValue)
			{
				instance.AddTheAdorner();
			}
			else
			{
				instance.RemoveTheAdorner();
			}
		}
		#endregion

		/// <inheritdoc />
		protected override void OnAttached()
		{
			base.OnAttached();

			if(AssociatedObject is FrameworkElement element)
			{
				element.IsVisibleChanged += Element_IsVisibleChanged;
				element.DataContextChanged += Element_DataContextChanged;
			}
		}

		/// <inheritdoc />
		protected override void OnDetaching()
		{
			base.OnDetaching();
			RemoveTheAdorner();
			_theAdorner = null;

			if(AssociatedObject is FrameworkElement element)
			{
				element.IsVisibleChanged -= Element_IsVisibleChanged;
				element.DataContextChanged -= Element_DataContextChanged;
			}
		}

		/// <summary>
		/// 附加元素可见性改变事件处理方法
		/// </summary>
		private void Element_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
		{
			if((bool)e.NewValue)
			{
				AddTheAdorner();
			}
			else
			{
				RemoveTheAdorner();
			}
		}

		/// <summary>
		/// 附加元素 DataContext 改变事件处理方法
		/// </summary>
		private void Element_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
		{
			if(Element != null)
			{
				Element.DataContext = e.NewValue;
			}
		}

		/// <summary>
		/// 添加装饰元素
		/// </summary>
		private void AddTheAdorner()
		{
			try
			{
				if(!IsShowAdorner)
					return;

				if(AssociatedObject == null)
					return;

				var adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
				if(adornerLayer == null)
					return;

				var adorners = adornerLayer.GetAdorners(AssociatedObject);
				if(adorners != null && adorners.Length > 0)
					return;

				if(_theAdorner == null)
				{
					_theAdorner = new BindableContainerAdorner(AssociatedObject) { Child = Element, };
				}
				else
				{
					if(adorners?.Contains(_theAdorner) ?? false)
					{
						adornerLayer.Remove(_theAdorner);
					}
				}

				adornerLayer.Add(_theAdorner);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}

		/// <summary>
		/// 移除装饰元素
		/// </summary>
		private void RemoveTheAdorner()
		{
			if(AssociatedObject == null)
				return;

			var adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
			if(adornerLayer == null)
				return;

			if(_theAdorner == null)
				return;

			adornerLayer.Remove(_theAdorner);
		}

		/// <summary>
		/// 移除所有的装饰元素
		/// </summary>
		private void RemoveAllAdorners()
		{
			if(AssociatedObject == null)
				return;

			var adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
			if(adornerLayer == null)
				return;

			var adorners = adornerLayer.GetAdorners(AssociatedObject);
			if(adorners == null)
				return;

			foreach(Adorner adorner in adorners)
			{
				adornerLayer.Remove(adorner);
			}
		}
	}
}
